package com.hmall.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.client.cart.CartClient;
import com.hmall.api.client.item.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.api.dto.OrderFormDTO;
import com.hmall.common.constants.MqConstants;
import com.hmall.common.exception.BadRequestException;
import com.hmall.common.utils.UserContext;
import com.hmall.trade.domain.po.Order;
import com.hmall.trade.domain.po.OrderDetail;
import com.hmall.trade.mapper.OrderMapper;
import com.hmall.trade.service.IOrderDetailService;
import com.hmall.trade.service.IOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2023-05-05
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final ItemClient itemClient;
    private final IOrderDetailService detailService;
    private final CartClient cartClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    private final RedissonClient redissonClient;

    @Override
    @GlobalTransactional
    public Long createOrder(OrderFormDTO orderFormDTO) throws InterruptedException {
        RLock lock = redissonClient.getLock("锁名称，要包含用户id"+UserContext.getUser());
        boolean success = lock.tryLock(3, 10, TimeUnit.SECONDS);
        if(!success){
            throw new RuntimeException("操作太频繁，请稍后再试");
        }
        // 1.订单数据
        Order order = new Order();
        try {
            // 1.1.查询商品
            List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
            // 1.2.获取商品id和数量的Map
            Map<Long, Integer> itemNumMap = detailDTOS.stream()
                    .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
            Set<Long> itemIds = itemNumMap.keySet();
            // 1.3.查询商品
            List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
            if (items == null || items.size() < itemIds.size()) {
                throw new BadRequestException("商品不存在");
            }
            // 1.4.基于商品价格、购买数量计算商品总价：totalFee
            int total = 0;
            for (ItemDTO item : items) {
                total += item.getPrice() * itemNumMap.get(item.getId());
            }
            order.setTotalFee(total);
            // 1.5.其它属性
            order.setPaymentType(orderFormDTO.getPaymentType());
            order.setUserId(UserContext.getUser());
            order.setStatus(1);
            // 1.6.将Order写入数据库order表中
            save(order);
            // 2.保存订单详情
            List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
            detailService.saveBatch(details);
            // 3.清理购物车商品
            cartClient.removeByItemIds(itemIds);
            // 4.扣减库存
            try {
                itemClient.deductStock(detailDTOS);
            } catch (Exception e) {
                throw new RuntimeException("库存不足！");
            }
        } finally {
            lock.unlock();
        }
        //todo 发送延迟消息。
        //     这里延迟消息的时间应该是35分钟，不过我们为了测试方便暂时设置为30秒。
        String msg="这是一条延迟消息，发送的时间是："+ LocalTime.now();
        rabbitTemplate.convertAndSend(MqConstants.DELAY_EXCHANGE_NAME, MqConstants.DELAY_ORDER_KEY, msg, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //给消息设置了消息头x-delay，值是3000毫秒
                message.getMessageProperties().setDelay(3000);
                return message;
            }
        });
        return order.getId();
    }

    @Override
    public void markOrderPaySuccess(Long orderId) {
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(2);
        order.setPayTime(LocalDateTime.now());
        updateById(order);
    }

    private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
        List<OrderDetail> details = new ArrayList<>(items.size());
        for (ItemDTO item : items) {
            OrderDetail detail = new OrderDetail();
            detail.setName(item.getName());
            detail.setSpec(item.getSpec());
            detail.setPrice(item.getPrice());
            detail.setNum(numMap.get(item.getId()));
            detail.setItemId(item.getId());
            detail.setImage(item.getImage());
            detail.setOrderId(orderId);
            details.add(detail);
        }
        return details;
    }
}
